package net.sudot.chess.business.controller.web;

import net.sudot.chess.exception.BusinessException;
import net.sudot.chess.business.controller.AbstractBaseController;
import net.sudot.chess.business.dto.PaymentItemDTO;
import net.sudot.chess.business.model.Customer;
import net.sudot.chess.business.model.OrderRecharge;
import net.sudot.chess.business.model.PaymentTransaction;
import net.sudot.chess.business.service.OrderRechargeService;
import net.sudot.chess.business.service.PaymentTransactionService;
import net.sudot.chess.business.service.PluginService;
import net.sudot.chess.plugin.payment.PaymentPlugin;
import net.sudot.commons.security.CsrfInterceptor;
import net.sudot.commons.security.LoginUser;
import net.sudot.commons.utils.ResponseMessage;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;

/**
 * 支付
 * <h2>支付跳转流程</h2>
 * <ol>
 * <li>
 * 提交支付请求
 * <p>在此请求里生成支付订单并调用支付前处理</p>
 * </li>
 * <li>支付前处理
 * <p>此请求主要处理用户身份认证并返回支付前处理视图从而发起支付处理</p>
 * </li>
 * <li>支付前处理视图
 * <p>主要处理用户身份认证,并发起实际支付处理</p>
 * </li>
 * <li>支付处理
 * <p>主要用于生成调用第三方支付接口的参数信息,并返回到支付处理视图发起第三方支付接口调用</p>
 * </li>
 * <li>支付处理视图
 * <p>发起第三方支付接口调用</p>
 * </li>
 * <li>支付后处理
 * <p>一般用于验证支付结果并跳转到支付结果视图</p>
 * </li>
 * <li>支付后结果视图
 * <p>用于展示支付结果,若为检测到支付结果,则在此视图重复发起支付结果检测请求</p>
 * </li>
 * <li>检查支付结果
 * <p>此接口主要用于第三方支付系统延迟返回支付结果信息时主动查询使用</p>
 * </li>
 * </ol>
 *
 * @author tangjialin on 2018-03-19.
 */
@Controller
@RequestMapping(value = "/payment")
public class PaymentController extends AbstractBaseController {

    @Resource
    private PluginService pluginService;
    @Resource
    private PaymentTransactionService paymentTransactionService;
    @Resource
    private OrderRechargeService orderRechargeService;

    /**
     * 提交支付请求
     *
     * @param customer        登录用户
     * @param paymentPluginId 支付插件ID
     * @param itemDTO         支付项
     *                        itemDTO.type    :(必需)支付类型
     *                        itemDTO.orderSn :(必需)订单编号
     *                        itemDTO.amount  :支付金额
     *                        itemDTO.userId  :支付用户
     * @return 返回支付前处理视图
     */
    @PostMapping("/submit")
    public ModelAndView submit(@LoginUser Customer customer, String paymentPluginId, PaymentItemDTO itemDTO) {
        PaymentPlugin paymentPlugin = pluginService.getPaymentPlugin(paymentPluginId);
        if (paymentPlugin == null || !paymentPlugin.getIsEnabled()) { throw new BusinessException("不支持的支付方式"); }
        String orderSn = itemDTO.getOrderSn();
        if (orderSn == null || orderSn.isEmpty()) { throw new BusinessException("订单不存在"); }
        PaymentTransaction.Type type = itemDTO.getType();
        if (type == null) { throw new BusinessException("无效的订单类型"); }
        // 支付金额
        BigDecimal amount = null;
        switch (type) {
            case RECHARGE:
                OrderRecharge order = orderRechargeService.findBySn(orderSn);
                if (order == null || !customer.getId().equals(order.getUserId())) {
                    throw new BusinessException("订单不存在");
                }
                if (order.getStatus() != OrderRecharge.Status.PENDING_PAYMENT) {
                    throw new BusinessException("订单" + order.getStatus().memo());
                }
                amount = order.getPayableAmount();
                itemDTO.setTarget(order.getId());
                break;
//            case BAIL:
//                break;
            default:
                throw new BusinessException("不支持的订单类型");
        }
        if (amount == null || BigDecimal.ZERO.compareTo(amount) >= 0) { throw new BusinessException("支付金额错误"); }
        itemDTO.setAmount(amount);
        itemDTO.setUserId(customer.getId());
        PaymentTransaction paymentTransaction = paymentTransactionService.generate(itemDTO, paymentPlugin);
        String payBeforeView = paymentPlugin.getPayBeforeUrl(paymentTransaction.getSn(), null);
        return new ModelAndView("redirect:" + payBeforeView);
    }

    /**
     * 支付前处理
     *
     * @param customer  登录用户
     * @param paymentSn 支付编号
     * @param extra     扩展参数
     * @param request   HttpServletRequest
     * @param response  HttpServletResponse
     * @return 返回支付处理视图
     */
    @CsrfInterceptor.Ignore
    @RequestMapping({"/before/{paymentSn}", "/before/{paymentSn}/{extra}"})
    public ModelAndView payBefore(@LoginUser Customer customer, @PathVariable String paymentSn, @PathVariable(required = false) String extra, HttpServletRequest request, HttpServletResponse response) {
        PaymentTransaction paymentTransaction = paymentTransactionService.findBySn(paymentSn);
        if (paymentTransaction == null || !customer.getId().equals(paymentTransaction.getUserId()) || paymentTransaction.hasExpired()) {
            throw new BusinessException("支付信息不存在或已过期");
        }
        if (paymentTransaction.getSuccess()) { return new ModelAndView(PaymentPlugin.DEFAULT_PAY_RESULT_VIEW_NAME); }
        String paymentPluginId = paymentTransaction.getPaymentPluginId();
        PaymentPlugin paymentPlugin = paymentPluginId == null || paymentPluginId.isEmpty() ? null : pluginService.getPaymentPlugin(paymentPluginId);
        if (paymentPlugin == null || !paymentPlugin.getIsEnabled()) { throw new BusinessException("不支持的支付方式"); }
        String payView = paymentPlugin.payBeforeHandle(paymentTransaction, null, extra, request, response);
        return new ModelAndView(payView);
    }

    /**
     * 支付处理
     *
     * @param customer  登录用户
     * @param paymentSn 支付编号
     * @param extra     扩展参数
     * @param request   HttpServletRequest
     * @param response  HttpServletResponse
     * @return 返回支付后处理视图
     */
    @CsrfInterceptor.Ignore
    @RequestMapping({"/pay/{paymentSn}", "/pay/{paymentSn}/{extra}"})
    public ModelAndView pay(@LoginUser Customer customer, @PathVariable String paymentSn, @PathVariable(required = false) String extra, HttpServletRequest request, HttpServletResponse response) {
        PaymentTransaction paymentTransaction = paymentTransactionService.findBySn(paymentSn);
        if (paymentTransaction == null || !customer.getId().equals(paymentTransaction.getUserId()) || paymentTransaction.hasExpired()) {
            throw new BusinessException("支付信息不存在或已过期");
        }
        if (paymentTransaction.getSuccess()) { return new ModelAndView(PaymentPlugin.DEFAULT_PAY_RESULT_VIEW_NAME); }
        String paymentPluginId = paymentTransaction.getPaymentPluginId();
        PaymentPlugin paymentPlugin = paymentPluginId == null || paymentPluginId.isEmpty() ? null : pluginService.getPaymentPlugin(paymentPluginId);
        if (paymentPlugin == null || !paymentPlugin.getIsEnabled()) { throw new BusinessException("不支持的支付方式"); }

        String payAfterView = paymentPlugin.payHandle(paymentTransaction, null, extra, request, response);
        return new ModelAndView(payAfterView);
    }

    /**
     * 支付后处理
     *
     * @param customer  登录用户
     * @param paymentSn 支付编号
     * @param extra     扩展参数
     * @param request   HttpServletRequest
     * @param response  HttpServletResponse
     * @return 返回支付成功处理视图
     */
    @CsrfInterceptor.Ignore
    @RequestMapping({"/after/{paymentSn}", "/after/{paymentSn}/{extra}"})
    public ModelAndView payAfter(@LoginUser Customer customer, @PathVariable String paymentSn, @PathVariable(required = false) String extra, HttpServletRequest request, HttpServletResponse response) {
        PaymentTransaction paymentTransaction = paymentTransactionService.findBySn(paymentSn);
        if (paymentTransaction == null || !customer.getId().equals(paymentTransaction.getUserId())) {
            throw new BusinessException("支付信息不存在");
        }
        if (paymentTransaction.getSuccess()) { return new ModelAndView(PaymentPlugin.DEFAULT_PAY_RESULT_VIEW_NAME); }

        String paymentPluginId = paymentTransaction.getPaymentPluginId();
        PaymentPlugin paymentPlugin = paymentPluginId == null || paymentPluginId.isEmpty() ? null : pluginService.getPaymentPlugin(paymentPluginId);
        if (paymentPlugin == null || !paymentPlugin.getIsEnabled()) { throw new BusinessException("不支持的支付方式"); }
        boolean isPaySuccess = paymentPlugin.isPaySuccess(paymentTransaction, null, extra, request, response);
        if (isPaySuccess) {
            paymentTransactionService.handle(paymentTransaction);
        }
        String payResultView = paymentPlugin.payAfterHandle(paymentTransaction, null, extra, true, request, response);
        return new ModelAndView(payResultView);
    }

    /**
     * 获取支付结果
     *
     * @param customer  登录用户
     * @param paymentSn 支付编号
     * @return 返回检测结果
     */
    @PostMapping("/result")
    @ResponseBody
    public ResponseMessage result(@LoginUser Customer customer, String paymentSn) {
        PaymentTransaction paymentTransaction = paymentTransactionService.findBySn(paymentSn);
        if (paymentTransaction == null || !customer.getId().equals(paymentTransaction.getUserId())) {
            return new ResponseMessage(false, "支付信息不存在");
        }
        return new ResponseMessage(paymentTransaction.getSuccess());
    }

    /**
     * 支付请求模拟
     *
     * @param redirect_uri 重定向地址
     * @return 返回重定向地址
     */
    @CsrfInterceptor.Ignore
    @PostMapping("/mock")
    public String mock(String redirect_uri) {
        return "redirect:" + redirect_uri;
    }
}
